#ifndef _MEMBER_BSTYLEDOCUMENT_H_
#define _MEMBER_BSTYLEDOCUMENT_H_

#include <BMap>
#include <BIcon>
#include <BImage>
#include <BString>
#include <BWidget>
#include <BStyleDocument>

#define styledoc_member(widget)		((member_BStyleDocument*)((BStyleDocument*)widget)->_ptr)

namespace BWE
{
	class member_BStyleDocument
	{
		friend class BStyleDocument;

		static inline char HtoI(char hex)
		{
			if (hex >= '0' && hex <= '9')
				return hex - '0';
			else if (hex >= 'a' && hex <= 'f')
				return hex - 'a' + 10;
			else if (hex >= 'A' && hex <= 'F')
				return hex - 'A' + 10;
			return 0;
		}
		static inline BByte HexToByte(const char cs[2])
		{
			char c0 = HtoI(cs[0]);
			char c1 = HtoI(cs[1]);
			return c0 * 16 + c1;
		}
		static inline bool StringToColor(BString& text, BColor& color)
		{
			if (text.empty() || text == "empty")
			{
				color.set(0, 0, 0, 0);
				return true;
			}
			if (text.beginWith('#'))
			{
				text.remove('#');
				if (text.size() == 6)
				{
					color.r() = HexToByte(text.cstr());
					color.g() = HexToByte(text.cstr() + 2);
					color.b() = HexToByte(text.cstr() + 4);
					color.a() = 255;
					return true;
				}
				if (text.size() == 8)
				{
					color.r() = HexToByte(text.cstr());
					color.g() = HexToByte(text.cstr() + 2);
					color.b() = HexToByte(text.cstr() + 4);
					color.a() = HexToByte(text.cstr() + 6);
					return true;
				}
				return false;
			}
			if (text.beginWith("rgb("))
			{
				int begin = text.find('(');
				text.remove(0, begin + 1);
				int end = text.find(')');
				text.remove(end, text.size());
				BStringList words;
				text.split(words, ',');
				if (words.size() == 3)
				{
					color.r() = words[0].toInt();
					color.g() = words[1].toInt();
					color.b() = words[2].toInt();
					color.a() = 255;
					return true;
				}
				return false;
			}
			if (text.beginWith("rgba("))
			{
				int begin = text.find('(');
				text.remove(0, begin + 1);
				int end = text.find(')');
				text.remove(end, text.size());
				BStringList words;
				text.split(words, ',');
				if (words.size() == 4)
				{
					color.r() = words[0].toInt();
					color.g() = words[1].toInt();
					color.b() = words[2].toInt();
					color.a() = words[3].toInt();
					return true;
				}
				return false;
			}
			if (text.contain(','))
			{
				BStringList words;
				text.split(words, ',');
				if (words.size() < 3 || words.size() > 4)
					return false;
				color.r() = words[0].toInt();
				color.g() = words[1].toInt();
				color.b() = words[2].toInt();
				color.a() = 255;
				if (words.size() == 4)
					color.a() = words[3].toInt();
				return true;
			}
			if (text.beginWith("white"))
			{
				color.set(255, 255, 255);
				return true;
			}
			if (text.beginWith("black"))
			{
				color.set(0, 0, 0, 255);
				return true;
			}
			if (text.beginWith("red"))
			{
				color.set(255, 0, 0);
				return true;
			}
			if (text.beginWith("green"))
			{
				color.set(0, 255, 0);
				return true;
			}
			if (text.beginWith("blue"))
			{
				color.set(0, 0, 255);
				return true;
			}
			if (text.beginWith("yellow"))
			{
				color.set(255, 255, 0);
				return true;
			}
			if (text.beginWith("fuchsia"))
			{
				color.set(255, 0, 255);
				return true;
			}
			if (text.beginWith("aqua"))
			{
				color.set(0, 255, 255);
				return true;
			}
			if (text.beginWith("gray"))
			{
				color.set(128, 128, 128);
				return true;
			}
			if (text.beginWith("silver"))
			{
				color.set(192, 192, 192);
				return true;
			}
			if (text.beginWith("purple"))
			{
				color.set(128, 128, 128);
				return true;
			}
			if (text.beginWith("maroon"))
			{
				color.set(128, 0, 0);
				return true;
			}
			if (text.beginWith("olive"))
			{
				color.set(128, 128, 0);
				return true;
			}
			if (text.beginWith("navy"))
			{
				color.set(0, 0, 128);
				return true;
			}
			if (text.beginWith("teal"))
			{
				color.set(0, 128, 128);
				return true;
			}
			return false;
		}
		static inline bool StringToAlign(BString& text, Align& align)
		{
			align = Align_None;
			if (text == "empty")
				align = Align_None;
			else if (text == "center")
				align = Align_Center;
			else if (text == "left-center")
				align = Align_LeftCenter;
			else if (text == "right-center")
				align = Align_RightCenter;
			else if (text == "top-center")
				align = Align_TopCenter;
			else if (text == "bottom-center")
				align = Align_BottomCenter;
			else
			{
				BString word;
				int pos = 0;
				while (pos < text.size())
				{
					pos = text.word(word, pos);
					if (word == ',')
						continue;
					else if (word == "left")
						((int&)align) |= Align_Left;
					else if (word == "right")
						((int&)align) |= Align_Right;
					else if (word == "top")
						((int&)align) |= Align_Top;
					else if (word == "bottom")
						((int&)align) |= Align_Bottom;
					else if (word == "hcenter")
						((int&)align) |= Align_HCenter;
					else if (word == "vcenter")
						((int&)align) |= Align_VCenter;
				}
			}
			return true;
		}
		static inline bool StringToForm(BString& text, Form& form)
		{
			form = Form_None;
			if (text == "icon-alone")
				form = Form_IconAlone;
			else if (text == "text-alone")
				form = Form_TextAlone;
			else if (text == "text-only")
				form = Form_TextOnly;
			else if (text == "icon-only")
				form = Form_IconOnly;
			else if (text == "icon-text")
				form = Form_IconText;
			else if (text == "text-icon")
				form = Form_TextIcon;
			else if (text == "text-under-icon" || text == "icon-above-text")
				form = Form_TextUnderIcon;
			else if (text == "icon-under-text" || text == "text-above-icon")
				form = Form_IconUnderText;
			else
				return false;
			return true;
		}
		static inline bool StringToSize(BString& text, BSize& size)
		{
			if (!text.isNumber())
			{
				return false;
			}
			if (text.contain(','))
			{
				BStringList words;
				text.split(words, ',');
				if (words.size() != 2)
					return false;
				size.width() = words[0].toInt();
				size.height() = words[1].toInt();
				return true;
			}
			int s = text.toInt();
			size.set(s, s);
			return true;
		}
		static inline bool StringToRect(const BString& text, BRect& rect)
		{
			BStringList words = text.split(',');
			if (words.size() == 4)
			{
				int x = words[0].toInt();
				int y = words[1].toInt();
				int w = words[2].toInt();
				int h = words[3].toInt();
				rect.set(x, y, w, h);
				return true;
			}
			return false;
		}
		static inline bool StringToMargin(const BString& text, BMargin& margin)
		{
			BStringList words = text.split(',');
			if (words.size() == 4)
			{
				margin.left() = words[0].toInt();
				margin.top() = words[1].toInt();
				margin.right() = words[2].toInt();
				margin.bottom() = words[3].toInt();
				return true;
			}
			return false;
		}
		static inline bool StringToBool(BString& text, bool& b)
		{
			if (text == "true" || text == "on")
			{
				b = true;
				return true;
			}
			if (text == "false" || text == "off")
			{
				b = false;
				return true;
			}
			return false;
		}

	public:
		member_BStyleDocument(BStyleDocument* styleDocument);
		~member_BStyleDocument();

		void read(BStyle* style, const BString& text, int& pos);
		void write(const BStyle* style, BString& text, int level);

	protected:
		bool readComment(const BString& text, int& pos, BString& comment);
		BStyle* findChild(BString& text, BStyle* style);
		BStyle* addStyle(BString& text, BStyle* parent);
		BStyle* addSubStyle(BString& text, int pos, BStyle* style);
		void readDesc(BString& text, BStyle* style);
		void analysis(BString& sign, BString& value, BStyle* style);

		void analysisTitle(member_BStyle* smem, BString& sign, BString& value);
		void analysisText(member_BStyle* smem, BString& sign, BString& value);
		void analysisBackground(member_BStyle* smem, BString& sign, BString& value);
		void analysisBorder(member_BStyle* smem, BString& sign, BString& value);
		void analysisPerch(member_BStyle* smem, BString& sign, BString& value);
		void analysisMargin(member_BStyle* smem, BString& sign, BString& value);
		void analysisRadius(member_BStyle* smem, BString& sign, BString& value);
		void analysisFont(member_BStyle* smem, BString& sign, BString& value);
		void analysisGroove(member_BStyle* smem, BString& sign, BString& value);
		void analysisGraph(member_BStyle* smem, BString& sign, BString& value);
		void analysisIcon(member_BStyle* smem, BString& sign, BString& value);
		void analysisImage(member_BStyle* smem, BString& sign, BString& value);
		void analysisBase(member_BStyle* smem, BString& sign, BString& value);
		void analysisArrow(member_BStyle* smem, BString& sign, BString& value);
		void analysisHandle(member_BStyle* smem, BString& sign, BString& value);
		void analysisWire(member_BStyle* smem, BString& sign, BString& value);
		void analysisSeparator(member_BStyle* smem, BString& sign, BString& value);
		void analysisGridLine(member_BStyle* smem, BString& sign, BString& value);
		void analysisHeader(member_BStyle* smem, BString& sign, BString& value);
		void analysisItem(member_BStyle* smem, BString& sign, BString& value);

		void resourceFont(member_BStyle* smem, BString& sign, BString& value);
		void resourceColor(member_BStyle* smem, BString& sign, BString& value);
		void resourceImage(member_BStyle* smem, BString& sign, BString& value);
		void resourceIcon(member_BStyle* smem, BString& sign, BString& value);
		void resourceTrans(member_BStyle* smem, BString& sign, BString& value);

		BImage* readImage(const BString& fileName);
		BIcon* readIcon(const BString& fileName);

		void assemble(BString& text, StyleRole srole, const BValue& value);
		inline void assembleString(BString& text, const char* sign, const BValue& value)
		{
			if (!value.is<BString>())
			{
				(BString&)message << "\tError[" << sign << "] : is not BString : " << '\n';
				return;
			}
			const BString& str = value;
			text << sign << ": " << str << ';';
		}
		inline void assembleBool(BString& text, const char* sign, const BValue& value)
		{
			if (!value.is<bool>())
			{
				(BString&)message << "\tError[" << sign << "] : is not bool : " << '\n';
				return;
			}
			bool b = value;
			text << sign << ": ";
			if (b)
				text << "true";
			else
				text << "false";
			text << ';';
		}
		inline void assembleInt(BString& text, const char* sign, const BValue& value)
		{
			if (!value.is<int>())
			{
				(BString&)message << "\tError[" << sign << "] : is not int : " << '\n';
				return;
			}
			int i = value;
			text << sign << ": " << i << ';';
		}
		inline void assembleFloat(BString& text, const char* sign, const BValue& value)
		{
			if (!value.is<float>())
			{
				(BString&)message << "\tError[" << sign << "] : is not float : " << '\n';
				return;
			}
			float f = value;
			text << sign << ": " << f << ';';
		}
		inline void assembleDouble(BString& text, const char* sign, const BValue& value)
		{
			if (!value.is<double>())
			{
				(BString&)message << "\tError[" << sign << "] : is not double : " << '\n';
				return;
			}
			double d = value;
			text << sign << ": " << d << ';';
		}
		inline void assembleSize(BString& text, const char* sign, const BValue& value)
		{
			if (!value.is<BSize>())
			{
				(BString&)message << "\tError[" << sign << "] : is not size : " << '\n';
				return;
			}
			const BSize& size = value;
			text << sign << ": " << size.width() << ", " << size.height() << ';';
		}
		inline void assembleIcon(BString& text, const char* sign, const BValue& value)
		{
			if (!value.is<BIcon>())
			{
				(BString&)message << "\tError[" << sign << "] : is not icon : " << '\n';
				return;
			}
			const BIcon* icon = value;
			text << sign << ": " << icon->name() << ';';
		}
		inline void assembleImage(BString& text, const char* sign, const BValue& value)
		{
			if (!value.is<BImage>())
			{
				(BString&)message << "\tError[" << sign << "] : is not image : " << '\n';
				return;
			}
			const BImage* image = value;
			text << sign << image->fileName() << ';';
		}
		inline void assembleColor(BString& text, const char* sign, const BValue& value)
		{
			if (!value.is<BColor>())
			{
				(BString&)message << "\tError[" << sign << "] : is not color : " << '\n';
				return;
			}
			const BColor& color = value;
			text << sign << ": " << color.r() << ", " << color.g() << ", " << color.b();
			if (color.a() < 255)
				text << ", " << color.a();
			text << ';';
		}
		inline void assmbleGridStyle(BString& text, const char* sign, const BValue& value)
		{
			if (!value.is<GridStyle>())
			{
				(BString&)message << "\tError[" << sign << "] : is not grid style : " << '\n';
				return;
			}
			text << sign << ": ";
			GridStyle gridStyle = value;
			switch (gridStyle)
			{
			case BWE::Grid_None:		text << "empty";		break;
			case BWE::Grid_Vertical:	text << "vertical";		break;
			case BWE::Grid_Horizontal:	text << "horizontal";	break;
			case BWE::Grid_Crossing:	text << "crossing";		break;
			default:					text << "unknown";		break;
			}
			text << ';';
		}
		inline void assembleGraph(BString& text, const char* sign, const BValue& value)
		{
			if (!value.is<Graph>())
			{
				(BString&)message << "\tError[" << sign << "] : is not graph." << '\n';
				return;
			}
			text << sign << ": ";
			Graph graph = value;
			switch (graph)
			{
			case Graph_None:				text << "empty";			break;
			case Graph_Space:				text << "space";			break;
			case Graph_Circle:				text << "circle";			break;
			case Graph_Circle_Fill:			text << "circle-fill";		break;
			case Graph_Square:				text << "square";			break;
			case Graph_Square_Fill:			text << "square-fill";		break;
			case Graph_Arrow_Up:			text << "arrow-up";			break;
			case Graph_Arrow_Up_Fill:		text << "arrow-up-fill";	break;
			case Graph_Arrow_Down:			text << "arrow-down";		break;
			case Graph_Arrow_Down_Fill:		text << "arrow-down-fill";	break;
			case Graph_Arrow_Left:			text << "arrow-left";		break;
			case Graph_Arrow_Left_Fill:		text << "arrow-left-fill";	break;
			case Graph_Arrow_Right:			text << "arrow-right";		break;
			case Graph_Arrow_Right_Fill:	text << "arrow-right-fill";	break;
			case Graph_Plus:				text << "plus";				break;
			case Graph_Minus:				text << "minus";			break;
			case Graph_Check:				text << "check";			break;
			case Graph_Radio:				text << "radio";			break;
			case Graph_Cross:				text << "cross";			break;
			case Graph_Minimize:			text << "minimize";			break;
			case Graph_Maximize:			text << "maximize";			break;
			case Graph_Normalize:			text << "normalize";		break;
			default:						text << "unknown";			break;
			}
			text << ';';
		}
		inline void assembleForm(BString& text, const char* sign, const BValue& value)
		{
			if (!value.is<Form>())
			{
				(BString&)message << "\tError[" << sign << "] : is not graph." << '\n';
				return;
			}
			text << sign << ": ";
			Form form = value;
			switch (form)
			{
			case Form_None:				text << "empty";			break;
			case Form_IconAlone:		text << "icon-alone";		break;
			case Form_TextAlone:		text << "text-alone";		break;
			case Form_TextOnly:			text << "text-only";		break;
			case Form_IconOnly:			text << "icon-only";		break;
			case Form_IconText:			text << "icon-text";		break;
			case Form_TextIcon:			text << "text-icon";		break;
			case Form_TextUnderIcon:	text << "text-under-icon";	break;
			case Form_IconUnderText:	text << "icon-under-text";	break;
			default:					text << "unknown";			break;
			}
			text << ';';
		}
		inline void assembleAlign(BString& text, const char* sign, const BValue& value)
		{
			if (!value.is<Align>())
			{
				(BString&)message << "\tError[" << sign << "] : is not align." << '\n';
				return;
			}
			text << sign << ": ";
			Align align = value;
			switch (align)
			{
			case Align_None:			text << "empty";		break;
			case Align_Left:			text << "left";			break;
			case Align_Right:			text << "right";		break;
			case Align_HCenter:			text << "hcenter";		break;
			case Align_Top:				text << "top";			break;
			case Align_Bottom:			text << "bottom";		break;
			case Align_VCenter:			text << "vcenter";		break;
			case Align_LeftTop:			text << "left-top";		break;
			case Align_LeftCenter:		text << "left-center";	break;
			case Align_LeftBottom:		text << "left-bottom";	break;
			case Align_RightTop:		text << "right-top";	break;
			case Align_RightCenter:		text << "right-center";	break;
			case Align_RightBottom:		text << "right-bottom";	break;
			case Align_TopCenter:		text << "top-center";	break;
			case Align_BottomCenter:	text << "bottom-center"; break;
			case Align_Center:			text << "center";		break;
			default:					text << "unknown";		break;
			}
			text << ';';
		}

	private:
		BStyleDocument*				boss;
		BString						path;
		int							line;
		int							linePos;
		BValue						message;
		BMap<BString, BImageHolder>	imageMap;
		BMap<BString, BIconHolder>	iconMap;
	};
}

#endif